package de.koller.aframe.util.noise.n3D;

import de.koller.aframe.util.misc.BufferedRandomFloat3D;
import de.koller.oceanFramework.OceanException;

public class CPerlin3D extends Noise3D {
	public static boolean PRINT_PROGRESS = false;
	
	public final int ox, oy, oz;
	private final BufferedRandomFloat3D crnd;
	private float persistence;
	private int steps;
	private int startStep;
	
	private int type = 0;
	
	public CPerlin3D( int ox, int oy, int oz, int resolution, BufferedRandomFloat3D crnd ) {
		super( new float[resolution+3][resolution+3][resolution+3] );
		
		this.ox = ox;
		this.oy = oy;
		this.oz = oz;
		this.crnd = crnd;
	}
	
	public CPerlin3D generate( int startStep, int steps, float persistence ) {
		this.persistence = persistence;
		this.steps = steps;
		this.startStep = startStep;
		
		for( int i = startStep; i < steps+startStep; i++ )
			handleStep( i );
		
		return this;
	}

	public CPerlin3D setType( int type ) {
		this.type = type;
		return this;
	}
	
	private void handleStep( int step ) {
		float amplitude = (float)Math.pow( persistence, step );
		int frequence = (int)Math.pow( 2, step );
		
		Noise3D n = new Noise3D( new float[ frequence + 3 ][ frequence + 3 ][ frequence + 3 ] );
		for( int ax = 0; ax < n.noise.length; ax++ )
			for( int ay = 0; ay < n.noise.length; ay++ )
				for( int az = 0; az < n.noise.length; az++ ) {
					n.noise[ax][ay][az] = crnd.get(
							(ox*frequence) + ax - 1,
							(oy*frequence) + ay - 1,
							(oz*frequence) + az - 1,
							step,
							type );
					}
		
		for( int az = 0; az < noise.length; az++ ) {
			for( int ax = 0; ax < noise.length; ax++ ) {
				for( int ay = 0; ay < noise.length; ay++ ) {
					float x = 1f / (float)noise.length * ax;
					float y = 1f / (float)noise.length * ay;
					float z = 1f / (float)noise.length * az;
				
					noise[ax][ay][az] += n.getValue( x, y, z ) * amplitude;
				}
			}
			
			if( PRINT_PROGRESS && az % 100 == 0 ) {
				String progress = "berechnen: " + step + " / " + (steps+startStep) + 
						" size: " + az + " / " + noise.length;
				System.out.println( progress );
			}
		
		}
		
	}

	@Override
	public void normalize( float height ) {
		super.normalize( height );
		
		throw new OceanException();
	}
	
}
